package cz.cvut.fit.web.nakupniSeznam.ws;

import java.util.ArrayList;
import java.util.HashMap;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cz.cvut.fit.web.nakupniSeznam.constants.DBConstants;
import cz.cvut.fit.web.nakupniSeznam.constants.WSConstants;
import cz.cvut.fit.web.nakupniSeznam.dao.CategoryDAO;
import cz.cvut.fit.web.nakupniSeznam.data.Category;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.CategoriesConverter;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.CategoryConverter;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.ErrorConverter;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.InfoConverter;

@Path("/user/{userId}/category")
public class Categories {
	
	private static final Logger LOG = LoggerFactory.getLogger(Categories.class);
	public static final String SAVE_COMPLETE = "category saving complete";
	public static final String LOG_OK = "ws succesfully called on category";
	
	@Context
	private UriInfo context;
	private String key;

	
	//====================== GET ======================//
	@GET
	@Produces(WSConstants.WS_PRODUCES)
	/**
	 * Returns informations about user's categories
	 * @return
	 */
	public Response getCategories(@Context HttpHeaders hh, @PathParam("userId") Long userId) {
		Response.ResponseBuilder builder = Response.status(Response.Status.OK);

		// try to find key in header
		key = AuthLibrary.getKey(hh, builder, LOG);
		if (key == null) {
			return builder.build();
		}

		// check key format
		if (AuthLibrary.checkKeyLength(key, builder, LOG) == false) {
			return builder.build();
		}

		// try to find element in DB
		try {
			java.util.List<Category> categories = CategoryDAO.getInstance()
					.getByOwner(key);
			CategoriesConverter converter = new CategoriesConverter(categories, context.getAbsolutePath());

			builder.entity(converter);
		} catch (NullPointerException ex) {
			builder.status(Response.Status.NOT_FOUND);
			builder.entity(new InfoConverter(WSConstants.RESULT_NOT_FOUND));
			LOG.error(WSConstants.RESULT_FAILED, ex);
			return builder.build();
		}

		LOG.debug(Categories.LOG_OK);
		return builder.build();
	}
	
	//====================== POST ======================//
	
	@POST
	@Produces(WSConstants.WS_PRODUCES)
	@Consumes(WSConstants.WS_CONSUMES)
	/**
	 * Create new list
	 * @return
	 */
	public Response postCategories(@Context HttpHeaders hh,
			CategoriesConverter converter) {
		Response.ResponseBuilder builder = Response
				.status(Response.Status.CREATED);

		// try to find key in header
		key = AuthLibrary.getKey(hh, builder, LOG);
		if (key == null) {
			return builder.build();
		}

		// check key format
		if (AuthLibrary.checkKeyLength(key, builder, LOG) == false) {
			return builder.build();
		}

		try {
			java.util.List<CategoryConverter> categories = converter.getCategories();
			java.util.List<Category> newCategories = new ArrayList<Category>();
			HashMap<Long, Long> idMap = new HashMap<Long, Long>();
			Long id;
			for (CategoryConverter c : categories) {
				Category category = c.retrieveRepresentation();
				//setting the category owner
				category.setOwner(key);
				// check if there is already category with such name for this owner
				id = checkCategoryPOST(category);
				idMap.put(id, c.getMobileId());
			
				newCategories.add(CategoryDAO.getInstance().getById(id));
				LOG.debug(Categories.SAVE_COMPLETE);
			}
			converter = new CategoriesConverter(newCategories, context.getAbsolutePath());
			for (CategoryConverter c : converter.getCategories()) {
				c.setMobileId(idMap.get(c.getId()));
			}
			builder.entity(converter);

		} catch (NullPointerException ex) {
			builder.status(Response.Status.BAD_REQUEST);
			builder.entity(new ErrorConverter(DBConstants.DB_BAD_DATA_FORMAT));
			LOG.error(WSConstants.RESULT_FAILED, ex);
			return builder.build();
		}

		LOG.debug(Categories.LOG_OK);
		return builder.build();
	}
	
	//====================== PUT ======================//
	@PUT
	@Produces(WSConstants.WS_PRODUCES)
	@Consumes(WSConstants.WS_CONSUMES)
	/**
	 * Create new list
	 * @return
	 */
	public Response putCategories(@Context HttpHeaders hh,
			CategoriesConverter converter) {
		Response.ResponseBuilder builder = Response
				.status(Response.Status.CREATED);

		// try to find key in header
		key = AuthLibrary.getKey(hh, builder, LOG);
		if (key == null) {
			return builder.build();
		}

		// check key format
		if (AuthLibrary.checkKeyLength(key, builder, LOG) == false) {
			return builder.build();
		}

		try {
			java.util.List<CategoryConverter> categories = converter.getCategories();
			for (CategoryConverter c : categories) {
				Category category = c.retrieveRepresentation();
				//setting the category owner
				category.setOwner(key);
				CategoryDAO.getInstance().save(category);
				LOG.debug(Categories.SAVE_COMPLETE);
			}
			builder.entity(new InfoConverter(Categories.SAVE_COMPLETE));

		} catch (NullPointerException ex) {
			builder.status(Response.Status.BAD_REQUEST);
			builder.entity(new ErrorConverter(DBConstants.DB_BAD_DATA_FORMAT));
			LOG.error(WSConstants.RESULT_FAILED, ex);
			return builder.build();
		}

		LOG.debug(Categories.LOG_OK);
		return builder.build();
	}
	
	//====================== DELETE ======================//
	
	//====================== OTHER =======================//
	
	/**
	 * Checks if there is already category with such name for this user in DB
	 * 
	 * @param category
	 * @return id of category in DB
	 */
	public Long checkCategoryPOST(Category cat) {
		Category category = CategoryDAO.getInstance().getByOwnerAndName(cat.getOwner(), cat.getName());
		if(category == null) {
			return CategoryDAO.getInstance().save(cat);
		}
		else {
			return category.getId();
		}
	}
}
